package de.swm.gwt.client.mobile.network;

import com.google.gwt.core.client.GWT;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;

import de.swm.gwt.client.mobile.ApplicationCache;
import de.swm.gwt.client.mobile.ApplicationRedirecter;
import de.swm.gwt.client.progressbar.IProgressBarNoCancelWaitDialog;
import de.swm.gwt.client.utils.Utils;



/**
 * This abstract class handels the logic if a new version becomes available while the current application is running.
 * 
 * @author wiese.daniel <br>
 *         copyright (C) 2011, SWM Services GmbH
 * 
 */
public abstract class AbstractVersionControlMonitor implements IVersionControlMonitor {

	private static final int HALF_MINUTE = 30;

	private static final int MINUTE = 60;

	private static final int MILISECONDS = 1000;

	/** Force update after 1.5 Minutes. **/
	private static final int FORCE_RELOAD_DELAY_IN_MS = (1 * MINUTE * MILISECONDS) + (HALF_MINUTE * MILISECONDS);

	@Inject
	private IProgressBarNoCancelWaitDialog progressBarNoCancelWaitDialog;

	/**
	 * Flag: Versionupgrade is running right now.
	 */
	private boolean updateIsRunning = false;

	/**
	 * Flag: Der cache wurde im Hintegrund bereits aktualisert.
	 */
	private boolean cacheUpdated = false;

	private final ApplicationCache cache;

	private Timer reloadTimer;



	/**
	 * Default constructor.
	 */
	public AbstractVersionControlMonitor() {
		if (ApplicationCache.isSupported()) {
			this.cache = ApplicationCache.getApplicationCache();
			registerCacheUpdateHandlers(cache);
		} else {
			this.cache = null;
		}
	}



	/**
	 * Wird stets uebermittelt wenn die aktuelle Serverversion bekanntgegeben wird. Dieses gescheid derzeit bei jeder
	 * ueberpruefung der Netzwerkverbindung.
	 * 
	 * @param newVersion18NMessage
	 *            the internationalized massage that a new version is available
	 * @param newVersion
	 *            the version id of the new version
	 * @param currentVerrsion
	 *            the version id of the installed version.
	 */
	public void updateHTML5Cache(String newVersion18NMessage, String newVersion, String currentVerrsion) {
		if (!updateIsRunning && GWT.isScript()) {
			updateIsRunning = true;
			Utils.console("Trying to update offline cache...");
			if (ApplicationCache.isSupported() && cache != null) {
				Window.alert(newVersion18NMessage + " - (" + currentVerrsion + ")/(" + newVersion + ") ");
				Utils.console("Trying to update offline cache...");
				if (cache.getStatus() == ApplicationCache.IDLE) {
					Utils.console("Cache is idle - triggering Update");
					cache.update();
				}

				// unendliche Progressbar bis zum Refresch der Anwendung
				AsyncCallback<Void> emptyCallback = new AsyncCallback<Void>() {

					@Override
					public void onFailure(Throwable caught) {

					}



					@Override
					public void onSuccess(Void result) {

					}
				};
				emptyCallback = progressBarNoCancelWaitDialog.start(emptyCallback);
				// storage leeren (Schritt1)
				Storage localStorage = Storage.getLocalStorageIfSupported();
				if (localStorage != null) {
					localStorage.clear();
				}

				// cache uwrde im Hintegrund bereits upgedated
				if (cacheUpdated) {
					updateIsRunning = false;
					ApplicationRedirecter.reloadApp();
				}

				// Auf Android wird der cache nicht getriggert > refresch nach x Minuten
				reloadTimer = new Timer() {
					@Override
					public void run() {
						updateIsRunning = false;
						ApplicationRedirecter.reloadApp();
					}
				};
				reloadTimer.schedule(FORCE_RELOAD_DELAY_IN_MS);
			} else {
				// nur relaoad
				updateIsRunning = false;
				ApplicationRedirecter.reloadApp();
			}
		}

	}



	/**
	 * Registriert die Hanlder fuer ein Cache update.
	 * 
	 * @param cache
	 *            der cache.
	 */
	private void registerCacheUpdateHandlers(final ApplicationCache cache) {

		cache.addEventListener("updateready", new EventListener() {
			@Override
			public void onBrowserEvent(Event event) {
				Utils.console("Cache Update erfolgreich");
				// den neuen cache benutzen
				cache.swapCache();
				Utils.console("Swap cache erfolgreich - reload folgt");
				cacheUpdated = true;
				// nur reload wenn Version-Meldung vom server bereits gekommen ist.
				if (updateIsRunning) {
					updateIsRunning = false;
					ApplicationRedirecter.reloadApp();
				}
			}
		}, false);

		cache.addEventListener("noupdate", new EventListener() {
			@Override
			public void onBrowserEvent(Event event) {
				Utils.console("Kein Update erforderlich");
			}
		}, false);

		cache.addEventListener("checking", new EventListener() {
			@Override
			public void onBrowserEvent(Event event) {
				Utils.console("Cache wird ueberprueft...");
			}
		}, false);

		cache.addEventListener("error", new EventListener() {
			@Override
			public void onBrowserEvent(Event event) {
				Utils.console("Fehler beim Update des Caches");
			}
		}, false);
	}

}
